/*
 * @Author: 0x9DEFA478
 * @Date: 2022-08-06 18:21:01
 * @LastEditTime: 2022-08-17 15:24:49
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * QQ:2652450237
 * ============================================================================================================================================
 * 
 * 
 * 
 *                                                                                               ************      ****************************
 *                                                                                             ************      ****************************  
 *                                                                                           ************      ****************************    
 *                                                                                         ************      ****************************      
 *                                                                                       ************      ************                        
 *                                                                                     ************      ************                          
 *                                                                                   ************      ************                            
 *                                                                                 ************      ************                              
 *                                                                               ************      ************                                
 *                                                                             ************      ************                                  
 *                                                                           ************      ************                                    
 *                                                                         ************      ************                                      
 *                                                                       ************      ************                                        
 *                                                                     ************      ************                                          
 *                                                                   ************      ************                                            
 *                                                                 ************      ************                                              
 *                                                               ************      ************                                                
 *                                                             ************      ************                                                  
 *                                                           ************      ************                                                    
 *                                                         ************      ************                                                      
 *                                                       ************      ************                                                        
 *                                                     ************      ************                                                          
 *                                                   ************      ************                                                            
 *                                                 ************      ************                                                              
 *                                               ************      ************                                                                
 *                                             ************      ************                                                                  
 *                                           ************      ************                                                                    
 *                                         ************      ************                                                                      
 *                                       ************      ************                                                                        
 *                                     ************      ************                                                                          
 *                                   ************      ************                                                                            
 *                                 ************      ************                                                                              
 *                               ************      ************                                                                                
 *                             ************      ************                                                                                  
 *                           ************      ************                                                                                    
 *                         ************      ************                                                                                      
 *       ****************************      ************                                                                                        
 *     ****************************      ************                                                                                          
 *   ****************************      ************                                                                                            
 * ****************************      ************                                                                                              
 * 
 * 
 * 
 * ============================================================================================================================================
 * 
 */
#ifndef H_NES_CPP_H
#define H_NES_CPP_H
#include "stdint.h"




class H_NES_CPP{

  public:

    enum class SampleRate:int{
      SampleRate_44100=44100,
      SampleRate_48000=48000,
      SampleRate_88200=88200,
      SampleRate_96000=96000,
      SampleRate_176400=176400,
      SampleRate_192000=192000,
      SampleRate_352800=352800,
      SampleRate_384000=384000
    };

    enum class TVStandards{
      NTSC=1,
      PAL=2,
      Dendy=3
    };

    class StandardControllerStatus{
      public:
        static const int Pad1P_A_Pos             =0;
        static const int Pad1P_B_Pos             =1;
        static const int Pad1P_AutoA_Pos         =2;
        static const int Pad1P_AutoB_Pos         =3;
        static const int Pad1P_Select_Pos        =4;
        static const int Pad1P_Start_Pos         =5;
        static const int Pad1P_Up_Pos            =6;
        static const int Pad1P_Down_Pos          =7;
        static const int Pad1P_Left_Pos          =8;
        static const int Pad1P_Right_Pos         =9;

        static const int Pad2P_A_Pos             =16;
        static const int Pad2P_B_Pos             =17;
        static const int Pad2P_AutoA_Pos         =18;
        static const int Pad2P_AutoB_Pos         =19;
        static const int Pad2P_Select_Pos        =20;
        static const int Pad2P_Start_Pos         =21;
        static const int Pad2P_Up_Pos            =22;
        static const int Pad2P_Down_Pos          =23;
        static const int Pad2P_Left_Pos          =24;
        static const int Pad2P_Right_Pos         =25;

        static const uint32_t Pad1P_A            =((uint32_t)0x1U)<<Pad1P_A_Pos     ;
        static const uint32_t Pad1P_B            =((uint32_t)0x1U)<<Pad1P_B_Pos     ;
        static const uint32_t Pad1P_AutoA        =((uint32_t)0x1U)<<Pad1P_AutoA_Pos ;
        static const uint32_t Pad1P_AutoB        =((uint32_t)0x1U)<<Pad1P_AutoB_Pos ;
        static const uint32_t Pad1P_Select       =((uint32_t)0x1U)<<Pad1P_Select_Pos;
        static const uint32_t Pad1P_Start        =((uint32_t)0x1U)<<Pad1P_Start_Pos ;
        static const uint32_t Pad1P_Up           =((uint32_t)0x1U)<<Pad1P_Up_Pos    ;
        static const uint32_t Pad1P_Down         =((uint32_t)0x1U)<<Pad1P_Down_Pos  ;
        static const uint32_t Pad1P_Left         =((uint32_t)0x1U)<<Pad1P_Left_Pos  ;
        static const uint32_t Pad1P_Right        =((uint32_t)0x1U)<<Pad1P_Right_Pos ;
        
        static const uint32_t Pad2P_A            =((uint32_t)0x1U)<<Pad2P_A_Pos     ;
        static const uint32_t Pad2P_B            =((uint32_t)0x1U)<<Pad2P_B_Pos     ;
        static const uint32_t Pad2P_AutoA        =((uint32_t)0x1U)<<Pad2P_AutoA_Pos ;
        static const uint32_t Pad2P_AutoB        =((uint32_t)0x1U)<<Pad2P_AutoB_Pos ;
        static const uint32_t Pad2P_Select       =((uint32_t)0x1U)<<Pad2P_Select_Pos;
        static const uint32_t Pad2P_Start        =((uint32_t)0x1U)<<Pad2P_Start_Pos ;
        static const uint32_t Pad2P_Up           =((uint32_t)0x1U)<<Pad2P_Up_Pos    ;
        static const uint32_t Pad2P_Down         =((uint32_t)0x1U)<<Pad2P_Down_Pos  ;
        static const uint32_t Pad2P_Left         =((uint32_t)0x1U)<<Pad2P_Left_Pos  ;
        static const uint32_t Pad2P_Right        =((uint32_t)0x1U)<<Pad2P_Right_Pos ;

        static int ButtonToPos(uint32_t Button);
        static uint32_t PosToButton(int Button_Pos);
        
    };

    /**
     * @brief 设置输出采样率
     * @param sampleRate 输出采样率
     * @return 无
     */
    void SetOutputSampleRate(SampleRate sampleRate);

    /**
     * @brief 设置总体音量
     * @param Volume 0~100的音量值
     * @return 无
     */
    void SetVolume_M(int Volume)noexcept;

    /**
     * @brief 设置左声道音量
     * @param Volume 0~100的音量值
     * @return 无
     */
    void SetVolume_L(int Volume)noexcept;

    /**
     * @brief 设置右声道音量
     * @param Volume 0~100的音量值
     * @return 无
     */
    void SetVolume_R(int Volume)noexcept;

    /**
     * @brief 设置方波通道的左右差分
     * @param PulseLR_Diff 差分值 -100~+100 小于0降低左声道方波2音量, 降低右声道方波1音量; 大于0降低左声道方波1音量, 降低右声道方波2音量
     * @return 无
     */
    void SetPulseLR_Diff(int PulseLR_Diff)noexcept;

    /**
     * @brief 设置电视标准 只能在停止状态下使用
     *        可能抛出字符串异常
     * @param tvStandards 电视标准
     * @return 无
     */
    void SetTelevisionStandards(TVStandards tvStandards);

    /**
     * @brief 设置Vblank触发NMI的延迟
     * @param VblankNMI_Delay VblankNMI延迟 延迟PPU时钟数
     * @return 无
     */
    void SetVblankNMI_Delay(int VblankNMI_Delay)noexcept;

    /**
     * @brief 设置MMC3触发计数器的延迟
     * @param MMC3_CountDelay 延迟PPU时钟数
     * @return 无
     */
    void SetMMC3_CountDelay(int MMC3_CountDelay)noexcept;

    /**
     * @brief 启动NES 
     *        可能抛出字符串异常
     * @param ROM 指向ROM
     * @return 无
     */
    void Start(void* ROM);

    /**
     * @brief 复位主机
     * @return 无
     */
    void Reset()noexcept;

    /**
     * @brief 停止运行的NES
     * @return 无
     */
    void Stop()noexcept;

    /**
     * @brief 获取存档大小
     *        可能抛出字符串异常
     * @return 存档长度
     */
    int GetProgressSize();

    /**
     * @brief 获取存档
     *        可能抛出字符串异常
     * @param Progress 用于返回存档指针 需要用户释放
     * @return 存档长度
     */
    int GetProgress(unsigned char** Progress);

    /**
     * @brief 加载存档
     *        可能抛出字符串异常
     * @param Progress 要加载的存档
     * @return 无
     */
    void LoadProgress(unsigned char* Progress);

    /**
     * @brief 获取状态
     * @return true:正常运行 false:已停止运行
     */
    bool GetIsRun();

    /**
     * @brief 构造NES
     * @param AudioSampleRate 输出音频采样率
     */
    H_NES_CPP(SampleRate AudioSampleRate);

    ~H_NES_CPP();

    /**
     * @brief 输出一帧图像 异步调用
     * @param ColorIndexArray 指向一帧的图像 其中的数据是颜色索引
     * @return 无
     */
    virtual void FrameOutput(unsigned char* ColorIndexArray)=0;

    /**
     * @brief 输出音频数据 异步调用
     * @param AudioSampleArray 音频数据
     * @param Length 数据长度 单位:样本数
     * @return 无
     */
    virtual void AudioOutput(int32_t* AudioSampleArray,int Length)=0;

    /**
     * @brief 获取标准控制器状态 异步调用
     * @return 控制器状态
     */
    virtual uint32_t GetStandardControllerStatus()=0;

  private:
    void* handle;
    TVStandards tvStandards;

    static int GetCPUFreq(TVStandards)noexcept;
};




#endif // H_NES_CPP_H
